Previous Book Contents Book Index Next

Inside Macintosh: 3D Graphics Programming With QuickDraw 3D /
Chapter 4 - Geometric Objects


About Geometric Objects

A geometric object (or a geometry) is an instance of the TQ3GeometryObject class. As you've seen, the TQ3GeometryObject class is a subclass of the TQ3ShapeObject, which is itself a subclass of the TQ3SharedObject class. As a result, a geometric object is associated with a reference count, which is incremented or decremented whenever you create or dispose of an instance of that type of object.

Currently, QuickDraw 3D provides many types of primitive geometric objects. A geometric object has one of these types:

kQ3GeometryTypeBox
kQ3GeometryTypeGeneralPolygon
kQ3GeometryTypeLine
kQ3GeometryTypeMarker
kQ3GeometryTypeMesh
kQ3GeometryTypeNURBCurve
kQ3GeometryTypeNURBPatch
kQ3GeometryTypePoint
kQ3GeometryTypePolygon
kQ3GeometryTypePolyLine
kQ3GeometryTypeTriangle
kQ3GeometryTypeTriGrid
These objects are described in detail later in this chapter, beginning on page 4-23. In most cases, the definitions of these objects are simple and obvious. For instance, a triangle is just a closed plane figure defined by three points, or vertices, in space. A simple polygon (object type kQ3GeometryTypePolygon) is a closed plane figure defined by a list of vertices. Only three of these types of geometric objects--meshes, NURB curves, and NURB patches--need special discussion. See "Meshes," beginning on page 4-6 for a description of meshes and "NURB Curves and Patches," beginning on page 4-10 for a description of NURB curves and patches.

Note
You can determine a geometric object's type by calling the Q3Geometry_GetType function, described later in this chapter.
QuickDraw 3D geometric objects are opaque. This means that you can edit the data associated with an object only by calling accessor functions provided by QuickDraw 3D. For instance, once you've created a triangle, you can alter its shape or position only indirectly, for example by calling the functions Q3Triangle_GetVertexPosition and Q3Triangle_SetVertexPosition.

Attributes of Geometric Objects

Every QuickDraw 3D geometric object can contain one or more optional sets of attributes, which define characteristics of all or part of the object, such as its color or other material properties. For example, QuickDraw 3D defines the data associated with a triangle like this:

typedef struct TQ3TriangleData {
   TQ3Vertex3D                vertices[3];
   TQ3AttributeSet            triangleAttributeSet;
} TQ3TriangleData;
As you can see, the triangle data consists of three vertices that define the triangle's position, together with a set of attributes that specify characteristics of the planar area enclosed by the lines connecting those vertices. A set of attributes is simply a collection of attributes, each of which consists of an attribute type and its associated data. Some common attribute types are diffuse color, specular color, surface normal vector, transparency, and so forth. You can, if you wish, define your own custom types of attributes and include them in attribute sets like any other kind of attribute.

Note
See the chapter "Attribute Objects" for complete information on the types of attributes defined by QuickDraw 3D and on defining custom attribute types. That chapter also shows how to create attribute sets.
You can associate a set of attributes with most parts of a geometric object. As you've seen, you can associate a set of attributes with the face of a triangle. You can also associate a set of attributes with one or more of the triangle's vertices. Similarly, a box can have a set of attributes that apply to the entire box as well as an attributes set for each of the six faces of the box. In this way, you can assign different colors to each of the box faces. Accordingly, QuickDraw 3D defines the data associated with a box like this:

typedef struct TQ3BoxData {
   TQ3Point3D                 origin;
   TQ3Vector3D                orientation;
   TQ3Vector3D                majorAxis;
   TQ3Vector3D                minorAxis;
   TQ3AttributeSet            *faceAttributeSet;
   TQ3AttributeSet            boxAttributeSet;
} TQ3BoxData;
The boxAttributeSet field is a set of attributes that apply to the entire box, and the faceAttributeSet field is a pointer to an array of attribute sets that apply to the six faces of the box.

Meshes

A mesh is a collection of vertices, faces, and edges that represent a topological polyhedron (that is, a solid figure composed of polygonal faces). The polyhedra represented by QuickDraw 3D meshes do not need to be closed, so that the meshes may have boundaries. Figure 4-1 illustrates a mesh.

Figure 4-1 A mesh

A mesh face is a polygonal figure that forms part of the surface of the mesh. QuickDraw 3D does not require mesh faces to be planar, but you can obtain unexpected results when rendering nonplanar mesh faces with a filled style. In addition, a mesh face can contain holes, as shown in Figure 4-2.

Figure 4-2 A mesh face with a hole

A mesh face is defined by a list of mesh vertices. The ordering of the vertices is unimportant; you can list the vertices of a mesh face in either clockwise or counterclockwise order. QuickDraw 3D internally attempts to maintain a consistent ordering of the vertices of all the faces of a mesh.

Because of their potential complexity, QuickDraw 3D treats meshes differently than it treats all other basic geometric objects. You create a basic geometric object by filling in a data structure that completely specifies that object (for example, a structure of type TQ3TriangleData) and then by passing that structure to the appropriate object-creating routine (for example, Q3Triangle_New). To create a mesh, however, you first create a new empty mesh (by calling Q3Mesh_New), and then you explicitly add vertices and faces to the mesh (by calling Q3Mesh_VertexNew and Q3Mesh_FaceNew).

Note
Although you can manipulate an edge in a mesh (for instance, assign an attribute set to it), you cannot explicitly add an edge to a mesh. Mesh edges are implicitly created or destroyed when the faces containing them are created or destroyed.
Because you can dynamically add or remove faces and vertices in a mesh, a mesh is always a retained object (that is, QuickDraw 3D maintains the mesh data internally) and never an immediate object. As a result, QuickDraw 3D does not supply routines to submit or write meshes in immediate mode. QuickDraw 3D builds an internal data structure that records the topology of a mesh (that is, the edge connections between all the faces and vertices in the mesh). For large models, this might require a large amount of memory. If your application does not need to use the topological information maintained by QuickDraw 3D (which you access by calling mesh iterator functions), you might want to use a trigrid (or a number of triangles, or a number of simple or general polygons) to represent a large number of interconnected polygons.

Note
See "Traversing Mesh Components, Vertices, Faces, and Edges," beginning on page 4-139, for information on the mesh iterator functions.
As you've seen, a face of a mesh can contain one or more holes. A hole is defined by a contour, which is just a list of vertices. You create a contour in a mesh face by creating a face that contains the vertices in the contour (by calling Q3Mesh_FaceNew) and then by converting the face into a contour (by calling Q3Mesh_FaceToContour). For optimal results, the face that contains the contour (called the container face) and the contour itself should be coplanar. In addition, the contour should lie entirely within the container face.

Note
See "Creating a Mesh," beginning on page 4-19 for sample code that creates a mesh.
The geometric structure of a mesh is completely defined by its faces, vertices, edges, and contours. For purposes of shading and picking, QuickDraw 3D defines several other parts of a mesh: corners, mesh parts, and components. A mesh corner (or a corner) is specified by a mesh face together with one of its vertices. (A face with five vertices therefore has five corners.) You can associate a set of attributes with each corner. The attributes in a corner override any existing attributes of the associated vertex. For example, you can use corners to achieve special shading effects, such as hard edges when applying a smooth shading to a mesh. When a face is being shaded smoothly, the normals used to determine the amount of shading are the normals of the face's vertices. Because a vertex and its normal may be associated with several faces, the light intensity computed by a shading algorithm is the same for all points around that vertex. As a result, the edges between appear smooth. To get a hard edge, you can assign different normals to the corners on opposite sides of the edge.

A mesh part object (or, more briefly, a mesh part) is a single distinguishable part of a mesh. You can use mesh parts to handle user picking in a mesh. When, for example, the user clicks on a mesh, you can interpret the click as a click on the entire mesh, on a face of a mesh, on an edge of the mesh, or on a vertex of the mesh. QuickDraw 3D signals your application that the user clicked on a mesh part by putting a reference to that mesh part in the shapePart field of a hit data structure. (Mesh parts are currently the only types of shape part objects.) You can then call QuickDraw 3D routines to get the mesh face, edge, or vertex that corresponds to the selected mesh part. See the chapter "Pick Objects" for complete details about mesh parts.

A mesh component (or a component) is a collection of connected vertices. (Two vertices are considered to be connected if an unbroken path of edges exists linking one vertex to the other.) For each mesh, QuickDraw 3D maintains information about the components in the mesh and updates that information whenever a face or vertex is added to or removed from a mesh. You can use QuickDraw 3D routines to iterate through the components in a mesh, and you can call Q3MeshPart_GetComponent to get the component in a mesh that was selected during picking. Mesh components cannot have attributes.

Mesh components are transient; that is, they are created and destroyed dynamically as the topology of the mesh changes. Whenever you change the topology (for example, by adding or deleting a vertex or face), QuickDraw 3D needs to update its internal list of mesh components. You can turn off this updating by calling the Q3Mesh_DelayUpdates function, and you can resume this updating by calling the Q3Mesh_ResumeUpdates function. For performance reasons, it's useful to delay updates while adding or deleting a large number of vertices or faces.

Note, however, that you cannot rely on some mesh functions to return accurate results if you call them while mesh updating is delayed. For instance, the Q3Mesh_GetNumComponents function is not guaranteed to return accurate results if mesh updating is delayed.

Note also that a vertex, edge, or face might be shifted from one component to another during a change in the topology of the mesh. To be safe, you should bracket all changes to the mesh topology by calls to Q3Mesh_DelayUpdates and Q3Mesh_ResumeUpdates, and you should not assume that mesh component functions will return reliable results until after you've called Q3Mesh_ResumeUpdates.

Note
You can duplicate a mesh by calling Q3Object_Duplicate. The duplicate mesh, however, might not preserve the ordering of components, faces, or vertices of the original mesh.

NURB Curves and Patches

QuickDraw 3D supports curves and surfaces that can be defined using nonuniform rational B-splines (NURBs), a class of equations defined by nonuniform parametric ratios of B-spline polynomials. A three-dimensional curve represented by a NURB equation is a NURB curve, and a three-dimensional surface represented by a NURB equation is a NURB patch. NURBs can be used to define very complex curves and surfaces, as well as some common geometric objects (for instance, the conic sections). NURB curves and patches are especially useful in 3D imaging because they are invariant under scale, rotate, translation, and perspective transformations of their control points. Figure 4-3 shows a sample NURB curve.

Figure 4-3 A NURB curve

A parametric curve is any curve whose points are represented by one or more functions of a single parameter (usually denoted by the letter t or u). The Cartesian coordinates (x, y) of a two-dimensional parametric curve can be represented generally by these two equations: x = x(u) y = y(u)

The Cartesian coordinates (x, y, z) of a three-dimensional parametric curve can be represented generally by these three equations x = x(u) y = y(u) z = z(u) :

For compactness, the two- or three-dimensional point is usually represented as a vector. A two-dimensional point has this vector: P(u) = [x(u) y(u)]

For example, a circle can be defined parametrically by a pair of equations: x = rcosu y = rsinu

Alternatively, a circle can be defined parametrically by this vector equation: P(u) = [rcosu rsinu]

A B-spline polynomial is a parametric equation of this form:

P(u) = i = 1 n + 1  BiNi,k(u)

where

             1     if x i ¾ u Ð x i + 1
Ni,1(u) =  {
             0     otherwise
                                                           
Ni,k(u) = (u-xiNi,k - 1(u) + (xi + k- u) N i + 1,k - 1 (u)
           xi + k - 1 - xi       xi + k - xi + 1

In these equations, the xi are elements of an array of real numbers, known as the knot vector, where each element is greater than or equal to the previous (that is, they are nondecreasing). The Bi are, algebraically, the coefficients of the polynomial representing the curve. Geometrically, they are the (x, y) positions (in a two-dimensional curve) of control points, which (together with the knot vector) define the shape of the particular curve of which they are a part. The control points and the knots define the curve's shape in this way: a position of a point on the curve at some parametric value u is a weighted combination of the positions of a subset of all the control points; the "weighting" is determined by the relative values of the knot vector.

Finally, a NURB curve is a curve defined by ratios of B-spline polynomials, where the values assigned to the parameter can be nonuniform. A NURB patch is a surface defined by ratios of B-spline surfaces, which are three-dimensional analogs of B-spline curves. A B-spline surface is a surface defined by a parametric equation of this form:

         N + 1   m + 1
                   wi,jBi,jNi,k(u)Mj,l(V)
         i = 1   j = 1
Q(u,v) =                                 
         N + 1   m + 1
                   wi,jNi,k(u)Mj,l(V)
         i = 1   j = 1
                  

where

             1       if xi ¾ u Ð x i + 1
Ni,l(u) = {
             0     otherwise
             
Ni,k(u) = (u-xiNi,k - 1(u) + (xi + k- u) N i + 1,k - 1 (u)
           xi + k - 1 - xi       xi + k - xi + 1

and

             1       if yj ¾ v Ð y j + 1
Mj,l(v) = {
             0     otherwise
             
Mj,k(v) = (v - yjMj,l - 1(v) + (yj + l- v) M j + 1, l - 1(v)
           yj + l - 1 - yj       yj + l - yj + 1

In these equations, the factors Bi,j are, algebraically, the coefficients of the polynomial representing the surface. Geometrically, they are the (x, y, z) coordinates of the control points that define the surface. The factors wi,j are the weights of those control points. The factors xi and yj are elements of arrays of real numbers, again called knot vectors. These vectors must be non-decreasing.

Surface Parameterizations

For some modeling operations--in particular, applying a texture to the surface of an object--QuickDraw 3D needs to perform a mapping between the texture and the surface. This mapping is usually specified using a pair of uv parametric spaces, one defined over the texture and one defined over the surface of the object. A uv parametric space is also called a parameterization. A uv parametric space applied to the surface of an object is a surface parameterization.

A texture is typically specified as a pixmap, that is, as a rectangular array of pixels. In that case, the texture has a simple uv parameterization (shown in Figure 4-4) that allows QuickDraw 3D to select pixels in the pixmap by varying u and v in the range 0 to 1. Figure 4-4 on page 4-14 shows the pixmap, with its origin in the upper-left corner; it also shows the standard pixmap parameterization, which maps the unit box from 0.0 to 1.0 along the u and v axes.

Figure 4-4 The standard uv parameterization for a pixmap

In addition to this texture parameterization, QuickDraw 3D uses another parameterization that picks out points on the surface of the object. For texture mapping, the most useful standard surface parameterization is any parameterization that results in the entire texture being mapped to the entire surface exactly once. QuickDraw 3D defines a standard surface parameterization for most of the primitive QuickDraw 3D geometric objects. In some cases, an object's standard surface parameterization is obtained from the object's natural surface parameterization (that is, a parameterization that defines the surface). For example, a NURB patch is naturally parameterized by its u and v knot vectors.

In other cases, however, there is no natural surface parameterization for an object, and QuickDraw 3D must define an arbitrary standard surface parameterization for it. For example, for a box, which has no natural surface parameterization, QuickDraw 3D uses the standard surface parameterization shown in Figure 4-5.

Figure 4-5 The standard surface parameterization of a box

Figure 4-6 shows the result of mapping the texture shown in Figure 4-4 onto the front face of a box.

Figure 4-6 A texture mapped onto a box

Some objects have neither a natural surface parameterization nor a standard surface parameterization supplied by QuickDraw 3D. For example, the faces of a mesh have neither type of parameterization. To apply a texture to such an object, you need to define your own custom surface parameterization. You do this by adding attributes of type kQ3AttributeTypeSurfaceUV to the vertices of the object. See Listing 4-3 on page 4-19 for details.

It's possible to modify the mapping used in applying a texture to a surface, by changing the surface's uv shading transform. (For example, you can rotate the texture any desired amount by installing the appropriate transformation matrix.) See the chapter "Shader Objects" for information on setting the uv transform used by a surface shader.

Note
To override an object's standard surface parameterization, or to define a custom surface parameterization for an object that has no standard surface parameterization, you need to manipulate the surface uv attributes of the object. See the chapter "Attribute Objects" for details.
The standard surface parameterizations of the QuickDraw 3D geometric objects are given in the section "Geometric Objects Reference."


Previous Book Contents Book Index Next

© Apple Computer, Inc.
11 JUL 1996